import SwiftUI
import AVFoundation

@Observable class DisplayItem: Identifiable, Equatable{
    var id=UUID()
    static func == (lhs: DisplayItem, rhs: DisplayItem) -> Bool{
        return lhs.id==rhs.id
    }
    enum FileStatus{
        case inProgress
        case finished
        case error
    }
    var source: String
    var target: String
    var title: String
    var status: FileStatus = .inProgress
    init(source: String, target: String, title: String){
        self.source=source
        self.target=target
        self.title=title
    }
}

@Observable class ExportHandler{
    var displayItems: [DisplayItem]=[]
    var status: ExportStatus = .notStarted

    func commonMetadata(key: AVMetadataKey, value: String) -> AVMetadataItem{
        let metadata=AVMutableMetadataItem()
        metadata.key = key as NSString
        metadata.keySpace = .common
        metadata.value = value as NSString
        return metadata
    }
    
    var tempDir=FileManager.default.temporaryDirectory.path+"/tempFolders"
    var tempDirName=""
    func export(_ dir: ExportDir) async {
        tempDirName="iOS \(dir.label)"
        tempDir="\(FileManager.default.temporaryDirectory.path)/tempFolders/\(tempDirName)"
        let basePath=dir.path
        displayItems=[]
        do{
            let re=Regex(/(?<dir>(.+\/)*)(?<name>.+)\.\w{3}/)
            // This line throws a detailed message if error occurs
            try FileManager.default.contentsOfDirectory(atPath: basePath)
            // Scan for audio files
            var sources: [String]=[]
            for item in FileManager.default.enumerator(atPath: basePath)!{
                if let filename=item as? String{
                    if (try re.firstMatch(in: filename) != nil){
                        sources.append(String(filename))
                    }
                }
            }
            // Remove existing temp dir
            if FileManager.default.fileExists(atPath: tempDir){
                try FileManager.default.removeItem(atPath: tempDir)
            }
            // Create temp dir
            try FileManager.default.createDirectory(atPath: tempDir, withIntermediateDirectories: true)
            print("Temp dir: \(tempDir)")
            
            var counter=0
            for filename in sources{
                let source=basePath+"/"+filename
                let match=try re.firstMatch(in: filename)!
                // File name without extension
                let name=String(match["name"]!.substring!)
                // Subdirectory
                let directory=String(match["dir"]!.substring!)
                if directory != ""{
                    // Create as needed
                    try FileManager.default.createDirectory(atPath: "\(tempDir)/\(directory)", withIntermediateDirectories: true)
                }
                // Target name and temp location
                let targetName="iOS-\(name).m4a".replacingOccurrences(of: " ", with: "")
                let target="\(tempDir)/\(directory)\(targetName)"
                
                // Title and artist metadata
                var titleName: String {
                    if let match=try? Regex(/^(?<name>.+)-EncoreInfinitum$/).firstMatch(in: name)?["name"]!.substring{
                        return "[iOS] \(String(match))"
                    }else if let match=try? Regex(/^(?<name>.+)-EncoreRemix$/).firstMatch(in: name)?["name"]!.substring{
                        return "[iOS-26] \(String(match))"
                    }else{
                        return "[iOS-Classic] \(name)"
                    }
                }
                let artistName="Apple"
                
                // Update display
                counter+=1
                status = .exporting(counter, sources.count, dir.label)
                let dispItem = DisplayItem(source: filename, target: directory+targetName, title: titleName)
                displayItems.append(dispItem)
                
                // Export as .m4a
                let audio=AVURLAsset(url: URL(filePath: source))
                let session=AVAssetExportSession(asset: audio, presetName: AVAssetExportPresetAppleM4A)!
                session.metadata=[
                    self.commonMetadata(key: .commonKeyTitle, value: titleName),
                    self.commonMetadata(key: .commonKeyArtist, value: artistName)
                ]
                do{
                    try await session.export(to: URL(filePath: target), as: .m4a)
                }catch{
                    dispItem.status = .error
                    throw error // execute outer catch statement
                }
                // Finished!
                dispItem.status = .finished
            }
            status = .finished
        }catch{
            status = .error(error.localizedDescription)
        }
    }
}
